﻿using System;
#if WINDOWS_PHONE
using StyleMVVM.Data.Collections;
#else
using System.Collections.Concurrent;
#endif
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.System.Threading;

namespace StyleMVVM.Utilities
{
	public sealed class CacheManager : ICacheManager
	{
		private static readonly object lockDefaultInstance = new object();
		private static volatile CacheManager defaultInstance;
		private ThreadPoolTimer timer;
		private TimeSpan collectionFrequency;
		private readonly ConcurrentDictionary<string, CacheEntry> cacheDict;

		public CacheManager()
		{
			cacheDict = new ConcurrentDictionary<string, CacheEntry>();

			CollectionFrequency = new TimeSpan(0, 1, 0);
		}

		public static CacheManager DefaultInstance
		{
			get
			{
				if (defaultInstance == null)
				{
					lock (lockDefaultInstance)
					{
						if (defaultInstance == null)
						{
							defaultInstance = new CacheManager();
						}
					}
				}

				return defaultInstance;
			}
		}

		public TimeSpan CollectionFrequency
		{
			get { return collectionFrequency; }
			set
			{
				if (timer != null)
				{
					timer.Cancel();
				}

				collectionFrequency = value;

				timer = ThreadPoolTimer.CreatePeriodicTimer(CollectHandler, collectionFrequency);
			}
		}

		public void Stop()
		{
			if (timer != null)
			{
				timer.Cancel();
			}
		}

		public void AddWithAbsoluteExpireTime(string key, object value, DateTimeOffset absoluteExpire)
		{
			cacheDict[key] = new CacheEntry(absoluteExpire - DateTime.Now, false, value);
		}

		public void AddWithSlidingExpireTime(string key, object value, TimeSpan slidingExpire)
		{
			cacheDict[key] = new CacheEntry(slidingExpire, true, value);
		}

		public void RemoveFromCache(string key)
		{
			CacheEntry oldValue;

			cacheDict.TryRemove(key, out oldValue);
		}

		public object GetValue(string key)
		{
			CacheEntry entry;

			if (cacheDict.TryGetValue(key, out entry))
			{
				return entry.GetValue();
			}

			return null;
		}

		private void CollectHandler(ThreadPoolTimer threadPoolTimer)
		{
			foreach (KeyValuePair<string, CacheEntry> keyValuePair in cacheDict)
			{
				if (keyValuePair.Value.Expired)
				{
					CacheEntry outValue;

					cacheDict.TryRemove(keyValuePair.Key, out outValue);
				}
			}
		}
	}
}